package com.zeroz.zookeeper.basic;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * ZooKeeper节点操作示例
 */
public class ZkNodeOperationsExample {
    private static final String CONNECT_STRING = "localhost:2181,localhost:2182,localhost:2183";
    private static final int SESSION_TIMEOUT = 5000;
    private static final CountDownLatch CONNECTED_LATCH = new CountDownLatch(1);
    
    private ZooKeeper zooKeeper;
    
    /**
     * 创建ZooKeeper客户端连接
     */
    public void connect() throws Exception {
        zooKeeper = new ZooKeeper(CONNECT_STRING, SESSION_TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                    System.out.println("已连接到ZooKeeper服务器");
                    CONNECTED_LATCH.countDown();
                }
            }
        });
        CONNECTED_LATCH.await();
    }
    
    /**
     * 创建节点
     */
    public String createNode(String path, String data) throws Exception {
        // 创建一个永久节点，使用开放权限
        return zooKeeper.create(path, data.getBytes(StandardCharsets.UTF_8), 
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }
    
    /**
     * 创建临时节点
     */
    public String createEphemeralNode(String path, String data) throws Exception {
        // 创建临时节点，客户端断开连接后会自动删除
        return zooKeeper.create(path, data.getBytes(StandardCharsets.UTF_8), 
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    }
    
    /**
     * 创建顺序节点
     */
    public String createSequentialNode(String path, String data) throws Exception {
        // 创建顺序节点，会在路径后面自动追加序号
        return zooKeeper.create(path, data.getBytes(StandardCharsets.UTF_8), 
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
    }
    
    /**
     * 检查节点是否存在
     */
    public boolean exists(String path) throws Exception {
        Stat stat = zooKeeper.exists(path, false);
        return stat != null;
    }
    
    /**
     * 获取节点数据
     */
    public String getData(String path) throws Exception {
        byte[] data = zooKeeper.getData(path, false, null);
        return new String(data, StandardCharsets.UTF_8);
    }
    
    /**
     * 设置节点数据
     */
    public Stat setData(String path, String data) throws Exception {
        return zooKeeper.setData(path, data.getBytes(StandardCharsets.UTF_8), -1);
    }
    
    /**
     * 列出子节点
     */
    public List<String> getChildren(String path) throws Exception {
        return zooKeeper.getChildren(path, false);
    }
    
    /**
     * 删除节点
     */
    public void deleteNode(String path) throws Exception {
        zooKeeper.delete(path, -1);
    }
    
    /**
     * 添加监听器监控节点数据变化
     */
    public void watchData(String path) throws Exception {
        zooKeeper.getData(path, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                if (event.getType() == Watcher.Event.EventType.NodeDataChanged) {
                    System.out.println("节点数据已变化: " + path);
                    try {
                        // 获取新数据
                        byte[] data = zooKeeper.getData(path, false, null);
                        System.out.println("新数据: " + new String(data, StandardCharsets.UTF_8));
                        
                        // 重新添加监听器
                        watchData(path);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, null);
        System.out.println("已添加数据变化监听器: " + path);
    }
    
    /**
     * 关闭ZooKeeper连接
     */
    public void close() throws Exception {
        if (zooKeeper != null) {
            zooKeeper.close();
            System.out.println("ZooKeeper连接已关闭");
        }
    }
    
    public static void main(String[] args) {
        ZkNodeOperationsExample example = new ZkNodeOperationsExample();
        
        try {
            // 连接到ZooKeeper
            example.connect();
            
            // 创建节点
            String nodePath = "/example";
            if (!example.exists(nodePath)) {
                String createdPath = example.createNode(nodePath, "Hello ZooKeeper!");
                System.out.println("创建节点: " + createdPath);
            }
            
            // 读取数据
            String data = example.getData(nodePath);
            System.out.println("节点数据: " + data);
            
            // 修改数据
            example.setData(nodePath, "Updated data");
            data = example.getData(nodePath);
            System.out.println("更新后数据: " + data);
            
            // 创建子节点
            String childPath = nodePath + "/child";
            if (!example.exists(childPath)) {
                example.createNode(childPath, "Child data");
            }
            
            // 列出子节点
            List<String> children = example.getChildren(nodePath);
            System.out.println("子节点列表: " + children);
            
            // 添加监听器
            example.watchData(nodePath);
            
            // 再次修改数据以触发监听器
            System.out.println("修改数据以触发监听器...");
            example.setData(nodePath, "Data changed for watcher");
            
            // 等待一下以便看到监听器效果
            Thread.sleep(2000);
            
            // 删除节点 (先删子节点再删父节点)
            example.deleteNode(childPath);
            example.deleteNode(nodePath);
            System.out.println("节点已删除");
            
        } catch (Exception e) {
            System.err.println("发生错误: " + e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                example.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
} 